package com.wm.blog_common.util;

import com.wm.blog_common.annotation.BlogSearch;
import com.wm.blog_common.base.BeanUtils;
import com.wm.blog_common.constatnt.CommonConstant;
import com.wm.blog_common.constatnt.RegexConstant;
import com.wm.blog_common.entity.TComment;
import com.wm.blog_common.entity.TUser;
import com.wm.blog_common.resp.BlogEsResp;
import com.wm.blog_common.resp.CommentItem;
import com.wm.blog_common.resp.IviewTreeResp;
import com.wm.blog_common.util.excel.ExcelDeep;
import com.wm.blog_common.util.excel.ExcelField;
import com.wm.blog_common.util.excel.FieldReflectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/***
 * @ClassName: CommonUtil
 * @Description: 通用工具类
 * @Author: wm_yu
 * @Create_time: 11:20 2020-3-19
 */
@Slf4j
public class CommonUtil {
    /**
     * 隐藏构造
     */
    private CommonUtil(){}


    /**
     * 生成token TODO
     * @return
     */
    public static String createToken(){
        return UUID.randomUUID().toString().replace("-","");
    }

    /**
     * 构建iview前端树形控件数据,递归深入处理
     * @param treeList
     * @return
     */
    public static void buildIvTree(List<MenuTree> treeList, List<IviewTreeResp> list){
        if(CollectionUtils.isEmpty(treeList)){
            return;
        }
        for (MenuTree menuTree : treeList) {
            if(ObjectUtils.isEmpty(menuTree)){
                continue;
            }
            IviewTreeResp treeResp = new IviewTreeResp();
            treeResp.setId(menuTree.getId());
            treeResp.setTitle(menuTree.getText());
            treeResp.setParentId(menuTree.getParentId());
            if(!CollectionUtils.isEmpty(menuTree.getChildren())) {
                List<IviewTreeResp> childrenList = new ArrayList<>();
                //递归处理
                buildIvTree(menuTree.getChildren(),childrenList);
                treeResp.setChildren(childrenList);
            }
            list.add(treeResp);
        }
    }


    /**
     * 循环递归处理需要回显的id,设置checked为true
     * @param respList
     * @param menuIdList
     */
    public static void dealChecked(List<IviewTreeResp> respList,List<Long> menuIdList){
        if(CollectionUtils.isEmpty(respList) || CollectionUtils.isEmpty(menuIdList)){
            return ;
        }
        for (IviewTreeResp resp : respList) {
            deal(resp,menuIdList);
            //解决一级菜单没有子菜单的问题,如:home页面  需要回显
            if(ObjectUtils.isNotEmpty(resp) && -1 == resp.getParentId() && CollectionUtils.isEmpty(resp.getChildren()) && menuIdList.contains(resp.getId())){
                resp.setChecked(true);
            }
        }
    }


    /**
     * 处理只有当某一级菜单的子菜单checked全部为true的时候,本身才为true
     * @param resp
     * @param menuIdList
     */
    private static void deal(IviewTreeResp resp,List<Long> menuIdList){
        List<IviewTreeResp> respList = resp.getChildren();
        if(CollectionUtils.isEmpty(respList) || CollectionUtils.isEmpty(menuIdList)){
            return ;
        }
        for (IviewTreeResp obj : respList) {
            //处理只有当某一级菜单的子菜单checked全部为true的时候,本身才为true
            if(menuIdList.contains(obj.getId())){
                obj.setChecked(true);
            }
            if(!CollectionUtils.isEmpty(obj.getChildren())){
                //递归处理子菜单
                deal(obj,menuIdList);
            }
        }
        int checkedSize = respList.stream().filter(IviewTreeResp::getChecked).collect(Collectors.toList()).size();
        resp.setChecked(respList.size() == checkedSize);
    }



    /**
     * 按指定大小,分隔集合，将集合按规定个数分为n个部分
     *
     * @param list
     * @param len
     * @return
     */
    public static <T> List<List<T>> splitList(List<T> list, int len) {
        if (list == null || list.size() == 0 || len < 1) {
            return null;
        }
        //返回结果
        List<List<T>> result = new ArrayList<>();
        //传入集合长度
        int size = list.size();
        //分隔后的集合个数
        int count = (size + len - 1) / len;
        for (int i = 0; i < count; i++) {
            List<T> subList = list.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
            result.add(subList);
        }
        return result;
    }



    /**
     * 获取excel标题字节数组,会深入处理
     * @param clzz 导出excel的字节对象  配合注解ExcelDeep+ExcelField使用
     * @return
     */
    public static List<String> getExcelHeaderList(Class<?> clzz) {
        List<String> headerList = new ArrayList<>();
        if (null != clzz) {
            //获取所有的字段
            Field[] fields = FieldReflectionUtil.getAllFields(clzz);
            Arrays.stream(fields).filter((Field field) -> !Modifier.isFinal(field.getModifiers())
                    && !Modifier.isStatic(field.getModifiers())).forEach(var -> {
                //判断是否有小对象
                if (var.isAnnotationPresent(ExcelDeep.class)) {
                    //渗透获取
                    try {
                        Object o = var.getType().newInstance();
                        Field[] typeFields = FieldReflectionUtil.getAllFields(o.getClass());
                        Arrays.stream(typeFields).filter((Field field) -> !Modifier.isFinal(field.getModifiers())
                                && !Modifier.isStatic(field.getModifiers())
                                && field.isAnnotationPresent(ExcelField.class)).forEach(var1 -> {
                            headerList.add(var1.getName());
                        });
                    } catch (InstantiationException | IllegalAccessException e) {
                        log.error("can not newInstance...:" + var.getType().getSimpleName(), e.getMessage(), e);
                    }
                }
                if (var.isAnnotationPresent(ExcelField.class)) {
                    headerList.add(var.getName());
                }
            });
        }
        return headerList;
    }


    public static String createSimpleToken(){
        return UUID.randomUUID().toString().replace("-","");
    }


    /**
     * 计算需要的线程数
     * @param total
     * @return
     */
    public static Integer getThreadCount(int total){
        return total / CommonConstant.DEFAULT_MAX_SIZE + 1;
    }



    /**
     * 评论时间字符串,
     * 1.不足1min,设置为刚刚
     * 2.大于1min 小于 60分钟 为   xx分钟前
     * 3.大于一小时不足一天,取下限  xxx小时前
     * 4.大于24h,按天计算  xxx天前
     */
    public static String dealCommentTime(Date time){
        if(ObjectUtils.isEmpty(time)){
            return null;
        }
        Date now = DateUtil.getCurrentDate();
        Long l = now.getTime() - time.getTime();
        if(l.intValue()/(1000*60) < 1){
            return "刚刚";
        }
        if(l.intValue()/(1000*60) < 60){
            return String.format("%s分钟前",l.intValue()/(1000*60));
        }
        if(l.intValue()/(1000*60*60) < 24){
            return String.format("%s小时前",l.intValue()/(1000*60*60));
        }
        return String.format("%s天前",l.intValue()/(1000*60*60*24));
    }


    /**
     * 字段null值校验,暂不支持复杂对象
     * @param obj
     * @return  爲空/为null返回true
     */
    public static boolean checkNullAndEmpty(Object obj){
        if(ObjectUtils.isEmpty(obj)){
            return true;
        }else if (obj instanceof CharSequence){
            return ((CharSequence) obj).length() == 0;
        }
        else if (obj instanceof Collection){
            return ((Collection) obj).isEmpty();
        }
        else if (obj instanceof Map){
            return ((Map) obj).isEmpty();
        }
        else if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        Class<?> clzz = obj.getClass();
        Field[] allFields = FieldReflectionUtil.getAllFields(clzz);
        for (Field field : allFields) {
            if(Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isAbstract(field.getModifiers())){
                continue;
            }
            if(!field.isAccessible()){
                field.setAccessible(true);
            }
            try {
                Object o = field.get(obj);
                //处理String,排除空字符串
                if(o instanceof String){
                    if(StringUtils.isNotEmpty((String) o)){
                        return false;
                    }
                }
                if(o instanceof Boolean){
                    //boolean类型且默认为true
                    if((Boolean) o){
                        return false;
                    }
                    continue;
                }
                if(o != null){
                    return false;
                }
                if(o instanceof Collection){
                    if(!((Collection) obj).isEmpty()){
                        return false;
                    }
                }
                if(o instanceof Map){
                    if(!((Map) obj).isEmpty()){
                        return false;
                    }
                }
                if(o != null && o.getClass().isArray() ){
                    if(Array.getLength(obj) > 0){
                        return false;
                    }
                }
            } catch (IllegalAccessException e) {
                log.error("get obj by reflect error{}:",field.getName(),e);
            }
        }
        return true;
    }


    /**
     * 根据博客的内容获取,到简介,简介最长100个汉字  只返回汉字组成的
     * @return
     */
    public static String createSummary(String content){
        if(StringUtil.isEmpty(content)){
            return content;
        }
        //匹配中文的正则+标点符号 todo
        String regex = "[\u4E00-\u9FA5]|[\\p{P}]";
        String regex2 = "[\u4E00-\u9FA5]";
        List<String> list = RegexUitl.matchList(content, regex2, 0, CommonConstant.BLOG_SUMMARY_LENGTH_LIMIT);
        return String.join("",list);
    }

    public static void main(String[] args) {
        String content = "<p class=\"source\" style=\"margin-top: 0px; margin-bottom: 10px; white-space: normal; padding: 0px; color: rgb(15, 15, 15); line-height: 28px; font-family: ����, Arial, Helvetica; font-size: 14px; background-color: rgb(240, 239, 226);\"><a href=\"https://so.gushiwen.org/shiwen/default.aspx?cstr=%e5%94%90%e4%bb%a3\" style=\"color: rgb(101, 100, 95); line-height: 24px; font-size: 12px;\">唐代</a><span style=\"line-height: 24px; color: rgb(101, 100, 95); font-size: 12px;\">：</span><a href=\"https://so.gushiwen.org/authorv_b90660e3e492.aspx\" style=\"color: rgb(101, 100, 95); text-decoration-line: none; line-height: 24px; font-size: 12px;\">李白</a></p><p style=\"white-space: normal;\">君不见黄河之水天上来，奔流到海不复回。<br/>君不见高堂明镜悲白发，朝如青丝暮成雪。<br/>人生得意须尽欢，莫使金樽空对月。<br/>天生我材必有用，千金散尽还复来。<br/>烹羊宰牛且为乐，会须一饮三百杯。<br/>岑夫子，丹丘生，将进酒，杯莫停。<br/>与君歌一曲，请君为我倾耳听。(倾耳听 一作：侧耳听)<br/>钟鼓馔玉不足贵，但愿长醉不愿醒。(不足贵 一作：何足贵；不愿醒 一作：不复醒)<br/>古来圣贤皆寂寞，惟有饮者留其名。(古来 一作：自古；惟 通：唯)<br/>陈王昔时宴平乐，斗酒十千恣欢谑。<br/>主人何为言少钱，径须沽取对君酌。<br/>五花马、千金裘，呼儿将出换美酒，与尔同销万古愁。</p><p style=\"white-space: normal;\"><br/></p><p><br/></p>";

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 1024; i++) {
            builder.append("这");
        }
        System.out.println(builder.toString());

        System.out.println(dealBlogMonthTime("2020-05"));
        //System.out.println(createSummary(content).length());

    }


    /**
     * 递归处理评论数据
     * @param parentList
     * @param childrenList
     * @return
     */

    /**

     * @param parentList
     * @param childrenList
     * @return
     */

    public static List<CommentItem> dealComment(List<TComment> parentList,List<TComment> childrenList,Map<Long, TUser> userMap){
        if(CollectionUtils.isEmpty(parentList)){
            return Collections.emptyList();
        }
        List<CommentItem> parentItemList = parentList
                .stream()
                .map(item -> {
                    return createItem(item,userMap);
                })
                .collect(Collectors.toList());
        List<CommentItem> childrenItemList = childrenList
                .stream()
                .map(item -> {
                    return createItem(item,userMap);
                })
                .collect(Collectors.toList());
        //loopDealComment(parentItemList,childrenItemList);   //该设计方案废弃
        /**
         * 评论总共只有二级,只有一层父级评论
         */
        buildCommentTree(parentItemList,childrenItemList);
        return parentItemList;
    }


    /**
     * 构建评论树
     * 1.只有2级,
     * @param parentItemList 一级评论
     * @param childrenItemList 非一级评论
     */
    private static void buildCommentTree(List<CommentItem> parentItemList,List<CommentItem> childrenItemList){
        for (CommentItem parent : parentItemList) {
            List<CommentItem> itemList = new ArrayList<>();
            for (CommentItem children : childrenItemList) {
                //必须归属同一博客
                if(parent.getBlogId().equals(children.getBlogId())){
                    if(parent.getId().equals(children.getToId())){
                        //说明是父子关系
                        itemList.add(children);
                    }
                    //需要处理该children下面是否还有children,如果有,一并加入这个集合
                    itemList.addAll(dealChildren(itemList, children, childrenItemList));
                    parent.setCommentItemList(itemList);
                }
            }
        }
    }


    /**
     * 递归构建
     * @param itemList 当前的子评论
     * @param parent 当前的评论
     * @param childrenItemList 所有的非一级评论
     */
    private static List<CommentItem> dealChildren(List<CommentItem> itemList,CommentItem parent,List<CommentItem> childrenItemList){
        if(ObjectUtils.isEmpty(itemList)){
            return Collections.emptyList();
        }
        List<CommentItem> list = new ArrayList<>();
        for (CommentItem children : childrenItemList) {
            if(children.getBlogId().equals(parent.getBlogId())){
                //同一篇博客的评论
                if(parent.getId().equals(children.getToId())){
                    list.add(children);
                    //递归处理
                    dealChildren(list,children,childrenItemList);
                }
            }
        }
        return list;
    }



    /**
     * 嵌套太深,废弃,改用另外一种设计
     *返回的格式:{
     *     "code": 200,
     *     "msg": "操作成功",
     *     "data": [
     *         {
     *             "id": "18",
     *             "userId": "2",
     *             "toId": "0",
     *             "content": "父级1",
     *             "blogId": "1",
     *             "status": 1,
     *             "createTime": "2020-05-19 16:28:13",
     *             "updateTime": "2020-05-19 16:28:13",
     *             "source": "流年博客",
     *             "type": 0,
     *             "commentTime": "22小时前",
     *             "commentItemList": [
     *                 {
     *                     "id": "19",
     *                     "userId": "2",
     *                     "toId": "18",
     *                     "content": "我是评论父级1的",
     *                     "blogId": "1",
     *                     "status": 1,
     *                     "createTime": "2020-05-19 16:29:07",
     *                     "updateTime": "2020-05-19 16:29:07",
     *                     "source": "流年博客",
     *                     "type": 0,
     *                     "commentTime": "22小时前"
     *                 }
     *             ]
     *         },
     *         {
     *             "id": "20",
     *             "userId": "1",
     *             "toId": "0",
     *             "content": "父级2",
     *             "blogId": "21",
     *             "status": 1,
     *             "createTime": "2020-05-19 16:34:17",
     *             "updateTime": "2020-05-19 16:34:17",
     *             "source": "流年博客",
     *             "type": 0,
     *             "commentTime": "22小时前",
     *             "commentItemList": [
     *                 {
     *                     "id": "28",
     *                     "userId": "1",
     *                     "toId": "20",
     *                     "content": "我是评论父级2的",
     *                     "blogId": "21",
     *                     "status": 1,
     *                     "createTime": "2020-05-20 11:32:05",
     *                     "updateTime": "2020-05-20 11:32:05",
     *                     "source": "流年博客",
     *                     "type": 0,
     *                     "commentTime": "3小时前",
     *                     "commentItemList": [
     *                         {
     *                             "id": "29",
     *                             "userId": "1",
     *                             "toId": "28",
     *                             "content": "我是我是评论父级2的",
     *                             "blogId": "21",
     *                             "status": 1,
     *                             "createTime": "2020-05-20 11:32:05",
     *                             "type": 0,
     *                             "commentTime": "3小时前",
     *                             "commentItemList": [
     *                                 {
     *                                     "id": "30",
     *                                     "userId": "1",
     *                                     "toId": "29",
     *                                     "content": "我是最后一个",
     *                                     "blogId": "21",
     *                                     "status": 1,
     *                                     "createTime": "2020-05-20 11:32:05",
     *                                     "type": 0,
     *                                     "commentTime": "3小时前"
     *                                 }
     *                             ]
     *                         }
     *                     ]
     *                 }
     *             ]
     *         }
     *     ],
     *     "success": true
     * }
     */
    @Deprecated
    private static void loopDealComment(List<CommentItem> parentList,List<CommentItem> childrenList,Map<Long, TUser> userMap){
        if(CollectionUtils.isEmpty(parentList)){
            return;
        }
        if(CollectionUtils.isEmpty(childrenList)){
            return;
        }
        //循环一级评论
        for (CommentItem parent : parentList) {
            List<CommentItem> itemList = new ArrayList<>();
            //循环非一级评论
            for (CommentItem children : childrenList) {
                //必须是属于同一片博客的
                if(parent.getBlogId().equals(children.getBlogId())){
                    if(parent.getId().equals(children.getToId())){
                        //这条子评论属于这个父级的
                        itemList.add(createItem(children,userMap));
                        parent.setCommentItemList(itemList);
                    }
                    //递归处理
                    loopDealComment(itemList,childrenList,userMap);
                }
            }
        }
    }


    private static CommentItem createItem(TComment comment,Map<Long,TUser> userMap){
        if(ObjectUtils.isEmpty(comment)){
            return new CommentItem();
        }
        CommentItem commentItem = new CommentItem();
        BeanUtils.copyProperties(comment,commentItem);
        if(ObjectUtils.isNotEmpty(comment.getCreateTime())){
            commentItem.setCommentTime(dealCommentTime(comment.getCreateTime()));
        }
        commentItem.setContent(comment.getContent());
        commentItem.setId(comment.getId());
        commentItem.setCommentUserName(userMap.getOrDefault(comment.getUserId(),new TUser()).getNickName());
        commentItem.setToCommentUserName(userMap.getOrDefault(comment.getToUserId(),new TUser()).getNickName());
        commentItem.setAvatar(userMap.getOrDefault(comment.getUserId(),new TUser()).getAvatar());
        return commentItem;
    }



  public static void dealBlogEsResp(BlogEsResp resp,Map<String,Object> highlightMap){
    if(ObjectUtils.isEmpty(resp)){
        return ;
    }
      Field[] fields = FieldReflectionUtil.getAllFields(BlogEsResp.class);
      List<Field> list = Arrays.stream(fields).filter(item -> item.isAnnotationPresent(BlogSearch.class)).collect(Collectors.toList());
      for (Field field : list) {
          field.setAccessible(true);
          String name = field.getName();
          Object value = highlightMap.getOrDefault(name, null);
          try {
              if(ObjectUtils.isNotEmpty(value)){
                 field.set(resp,value);
              }
          } catch (IllegalAccessException e) {
              log.error("反射处理高亮数据异常:{}",e.getMessage(),e);
          }
      }
  }

    /**
     * 将格式为: 2020-05格式的时间转换为 2020年5月的字符串
     * @param dateTime
     * @return
     */
    public static String dealBlogMonthTime(String dateTime) {
        if(StringUtil.isEmpty(dateTime)){
            return dateTime;
        }
        String[] split = dateTime.split("-");
        return String.format("%s年%s月",split[0],split[1]);
    }


    /**
     * 校验按钮权限的url,格式必须是: /英文(不区分大小写)/英文(不区分大小写) 或者 英文(不区分大小写)/英文(不区分大小写),否则返回false
     * @param url
     * @return
     */
    public static boolean checkButtonUrl(String url){
        if(StringUtil.isEmpty(url)){
            return false;
        }
        Boolean check = RegexUitl.check(url, RegexConstant.BUTTON_URL_REGENX);
        return check;
    }



}
